/*
 * Copyright (c) 2011-2022, baomidou (jobob@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baomidou.mybatisplus.advance.injector.processor;

import com.baomidou.mybatisplus.advance.injector.ASTBuilder;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;

/**
 * 为类里面每个属性都生成一个方法
 * 比如 userName 属性会自动生成一个 userName()方法
 * 大概使用方式：
 * private preFieldName = "";
 * public User userName(){
 * preFieldName = "userName";
 * return this;
 * }
 * 这样调用了userName后，在调用别的方法比如like(String args) 就知道是username去like
 *
 * @author wanglei
 * @since 2022-03-14
 */
public class GenFieldsMethodProcessor implements MybatisPlusAPTProcessor {

    @Override
    public void generate(ASTBuilder astBuilder) {
        if(!astBuilder.hasField("preFieldName")){
            // 先生成  private preFieldName = "";
            JCTree.JCVariableDecl preFieldName = astBuilder.genField("preFieldName", "java.lang.String", astBuilder.getTreeMaker().Literal(""));
            astBuilder.getJcClassDecl().defs = astBuilder.getJcClassDecl().defs.prepend(preFieldName);
            //为每个字段都生成一个方法
            astBuilder.getFields().forEach(field -> {
                //不包含此方法才生成
                if (!astBuilder.hasMethod(field.name.toString())) {
                    astBuilder.addMethod(genFieldMethod(field, astBuilder));
                }
            });
        }
    }

    /**
     * 生成和字段同名的方法
     *
     * @param jcVariableDecl 字段
     * @param astBuilder     ASTBuilder
     * @return
     */
    private JCTree.JCMethodDecl genFieldMethod(JCTree.JCVariableDecl jcVariableDecl, ASTBuilder astBuilder) {
        TreeMaker treeMaker = astBuilder.getTreeMaker();
        JCTree.JCExpression retrunType = treeMaker.Ident(astBuilder.getJcClassDecl().getSimpleName());//返回值类型 为当前类
        //方法名和字段名相同
        Name methodName = jcVariableDecl.name;
        // this.preFieldName = "fieldName";
        JCTree.JCStatement jcStatement = treeMaker.Exec(treeMaker.Assign(
                treeMaker.Select(treeMaker.Ident(astBuilder.getNames().fromString("this")), astBuilder.getNames().fromString("preFieldName")),
                treeMaker.Literal(jcVariableDecl.name.toString())));
        List<JCTree.JCStatement> jcStatementList = List.nil();
        jcStatementList = jcStatementList.append(jcStatement);
        //生成return语句: return this;
        JCTree.JCReturn returnStatement = treeMaker.Return(
                treeMaker.Ident(astBuilder.getNames().fromString("this"))
        );
        jcStatementList = jcStatementList.append(returnStatement);
        JCTree.JCBlock jcBlock = treeMaker.Block(0, jcStatementList);//代码块
        JCTree.JCMethodDecl jcMethodDecl = treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC), methodName, retrunType, List.nil(), List.nil(), List.nil(), jcBlock, null);
        return jcMethodDecl;
    }
}
